#include "Ds1307.h"

void Ds1307::initialize(){
  Wire.begin();
}

void Ds1307::readData(){ //block interputs ??
  Wire.beginTransmission(DeviceAddressID);
  Wire.write(index0);    ///move to 0 index
  if(checkIfConnectionWorked() == true){
    Wire.requestFrom(DeviceAddressID, dsRecive7Byte);
    if(checkIfDeviceWillRespond() == true){
      controlDat = Wire.read();
      second = bcd2dec((controlDat & DeviceStartClock));    //remove controlData from seconds
      checkErrorData(second);
      minute = bcd2dec(Wire.read());
      checkErrorData(minute);
      //hour = (Wire.read() & 0x3f);  // mask assumes 24hr clock
      hour = bcd2dec(Wire.read());
      checkErrorData(hour);
      weekDay = bcd2dec(Wire.read());
      checkErrorData(weekDay);
      day = bcd2dec(Wire.read());
      checkErrorData(day);
      month = bcd2dec(Wire.read());
      checkErrorData(month);
      year = bcd2dec(Wire.read());
      checkErrorData(year);
      checkDeviceClockWork( controlDat );
    }
  }
}

void Ds1307::setData(void){

  stopDeviceClock();
  writeDataToDS1307();
  startDeviceClock();
  writeDataToDS1307();

}

void Ds1307::setSqwOutput(uint8_t set) // set to off, 1Hz,4k,8k,32k
{
  Wire.beginTransmission(DeviceAddressID);
  Wire.write(index7); // move pointer to SQW address
  Wire.write(set); // sends 0x10 (hex) 00010000 (binary)
  checkIfConnectionWorked(); 
}

//---private

void Ds1307::checkErrorData(uint8_t t){
  if(t == 165) errorData++;
}

void Ds1307::writeDataToDS1307(){
  Wire.beginTransmission(DeviceAddressID);
  Wire.write(index0);    ///move to 0 index

  Wire.write(dec2bcd(second));
  Wire.write(dec2bcd(minute));
  Wire.write(dec2bcd(hour));
  Wire.write(dec2bcd(weekDay));
  Wire.write(dec2bcd(day));
  Wire.write(dec2bcd(month));
  Wire.write(dec2bcd(year));

  checkIfConnectionWorked(); 

}

void Ds1307::stopDeviceClock(){
  second |= DeviceStopClock; 
}

void Ds1307::startDeviceClock(){
  second &= DeviceStartClock;
}

void Ds1307::beginI2CtoDS1307(void){
  Wire.beginTransmission(DeviceAddressID);
}

boolean Ds1307::checkIfConnectionWorked(){     // 0:success
  if( Wire.endTransmission() == 0){          // 1:data too long to fit in transmit buffer
    deviceResponded = true;                  // 2:received NACK on transmit of address
    return true;                             // 3:received NACK on transmit of data
  }                                          // 4:other error 
  else{
    deviceResponded = false;
    return false;
  }
}

boolean Ds1307::checkIfDeviceWillRespond(){
  if( Wire.available() < dsRecive7Byte){
    deviceResponded = false;
    return false;
  }  
  else{
    deviceResponded = true;
    return true;
  }
}

void Ds1307::checkDeviceClockWork(uint8_t sec){
  if(sec & DeviceStopClock) deviceClockWork = false;
  else deviceClockWork = true;
}

// Convert Decimal to Binary Coded Decimal (BCD)
uint8_t Ds1307::dec2bcd(uint8_t num){
  return ((num/10 * 16) + (num % 10));
}

// Convert Binary Coded Decimal (BCD) to Decimal
uint8_t Ds1307::bcd2dec(uint8_t num){
  return ((num/16 * 10) + (num % 16));
}



//--------public

void Ds1307::stopDevice(void){
  stopDeviceClock();
  writeDataToDS1307();
}

void Ds1307::startDevice(void){
  startDeviceClock();
  writeDataToDS1307();
}

boolean Ds1307::isDeviceResponded(){
  return deviceResponded;
}

boolean Ds1307::isDeviceClockWork(void){
  return deviceClockWork;
}

byte Ds1307::getYear(void){
  return year;
}

byte Ds1307::getMonth(void){
  return month;
}

byte Ds1307::getDay(void){
  return day;
}

byte Ds1307::getWeekDay(void){
  return weekDay;
}

byte Ds1307::getHour(void){
  return hour;
}

byte Ds1307::getMinute(void){
  return minute;
}

byte Ds1307::getSecond(void){
  return second;
}

byte Ds1307::getControlData(void){
  return controlDat;
}

byte Ds1307::getErrorCounter(void){
  return errorData;
}

void Ds1307::setYear(uint8_t t){
  year = t;
}
void Ds1307::setMonth(uint8_t t){
  month = t;
}
void Ds1307::setDay(uint8_t t){
  day = t;
}

void Ds1307::setWeekDay(uint8_t t){
  weekDay = t;
}

void Ds1307::setHour(uint8_t t){
  hour = t;
}

void Ds1307::setMinute(uint8_t t){
  minute = t;
}

void Ds1307::setSecond(uint8_t t){
  second = t;
}


